package com.authine.cloudpivot.ext.utils;

import com.alibaba.cola.exception.BizException;
import com.alibaba.fastjson.JSON;
import com.authine.cloudpivot.metadata.design.dto.clientobject.domainmodel.schema.Properties;
import com.authine.cloudpivot.metadata.design.dto.clientobject.domainmodel.schema.ValueType;
import com.authine.common.util.ObjectMapperUtils;
import com.authine.mvp.app.launcher.domain.AddrFormat;
import com.authine.mvp.app.launcher.domain.AttachmentFormat;
import com.authine.mvp.app.launcher.domain.SelectorFormat;
import com.authine.mvp.app.launcher.dto.errorcode.ErrorCodeEnum;
import com.authine.mvp.app.org.dto.domainvo.DeptOrUserVO;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.stream.Collectors;

public class BoUtils {
    private static final Logger log = LoggerFactory.getLogger(BoUtils.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();

    public BoUtils() {
    }

    public static Map<String, Object> bo2Map(Object obj) {
        try {
            Map<String, Object> map = (Map)objectMapper.readValue(objectMapper.writeValueAsString(obj), new TypeReference<Map<String, Object>>() {
            });
            return map;
        } catch (JsonProcessingException var3) {
            throw bizException(var3.getMessage());
        }
    }

    public static <T> T Map2Bo(Map<String, Object> map, Class<T> clazz) {
        try {
            T t = objectMapper.readValue(objectMapper.writeValueAsString(map), clazz);
            return t;
        } catch (JsonProcessingException var4) {
            throw bizException(var4.getMessage());
        }
    }

    public static <T> T json2Object(String json, Class<T> clazz) {
        try {
            T t = objectMapper.readValue(json, clazz);
            return t;
        } catch (Exception var4) {
            throw bizException(var4.getMessage());
        }
    }

    public static String toJsonString(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception var2) {
            var2.printStackTrace();
            return null;
        }
    }

    public static <T> T copy2Class(Object source, Class<T> clazz) {
        try {
            return objectMapper.readValue(toJsonString(source), clazz);
        } catch (JsonProcessingException var3) {
            var3.printStackTrace();
            return null;
        }
    }

    public static <T> List<T> copy2List(Object source, Class<T> clazz) {
        try {
            return (List)objectMapper.readValue(toJsonString(source), new TypeReference<List<T>>() {
            });
        } catch (JsonProcessingException var3) {
            var3.printStackTrace();
            return null;
        }
    }

    public static String getOrgId(Object org) {
        if (org == null) {
            return null;
        } else if (org instanceof String) {
            if (((String)org).startsWith("{")) {
                try {
                    return ((JsonNode)objectMapper.readValue((String)org, JsonNode.class)).get("id").asText();
                } catch (JsonProcessingException var2) {
                    var2.printStackTrace();
                    return null;
                }
            } else if (((String)org).startsWith("[")) {
                try {
                    return ((JsonNode)objectMapper.readValue((String)org, new TypeReference<JsonNode>() {
                    })).get(0).get("id").asText();
                } catch (JsonProcessingException var3) {
                    var3.printStackTrace();
                    return null;
                }
            } else {
                return (String)org;
            }
        } else if (org instanceof DeptOrUserVO) {
            return ((DeptOrUserVO)org).getId();
        } else if (org instanceof SelectorFormat) {
            return ((SelectorFormat)org).getId();
        } else if (org instanceof Map) {
            return (String)((Map)org).get("id");
        } else {
            try {
                return String.valueOf(FieldUtils.readField(org, "id"));
            } catch (IllegalAccessException var4) {
                var4.printStackTrace();
                return null;
            }
        }
    }


    /**
     * 比较两个对象业务字字段值是否全部相等,
     * 前端提交数据 经过 convert,  后端数据通过 boService.load 获取
     *
     * @return true 相等, false 不相等
     */
    public static boolean boCompare(List<Properties> ps, Map<String, Object> newData, Map<String, Object> oldData) {
        log.info("\n\n\n");
        // 所有元素都相等,anyMatch 返回 false, 任一元素不相等 anyMatch 返回 true, 所以要取反
        return !ps.stream().filter(a -> !a.getIsSystemProperty()).anyMatch(p -> !BoFieldCompare(p, newData, oldData));
    }

    /**
     * 比较对象业务指定字段值是否相等
     *
     * @param p
     * @param newData
     * @param oldData
     * @return
     */
    public static boolean BoFieldCompare(Properties p, Map<String, Object> newData, Map<String, Object> oldData) {
        String code = p.getCode();
        Object newVal = newData.get(code);
        Object oldVal = oldData.get(code);
        ValueType valueType = p.getValueType();

        boolean equals;

        if (newVal == null) {
            equals = oldVal == null;
        } else if (oldVal == null) {
            equals = newVal == null;
        } else {
            if (ValueType.RADIO_PERSON == valueType || ValueType.RADIO_DEPARTMENT == valueType) {
                SelectorFormat val1 = ObjectMapperUtils.fromJSON(JSON.toJSONString(newVal), SelectorFormat.class);
                SelectorFormat val2 = ((List<SelectorFormat>) oldVal).stream().findFirst().get();
                equals = val1.equals(val2);
            } else if (ValueType.ATTACHMENT == valueType || ValueType.IMAGE == valueType) {
                List<AttachmentFormat> val1 = ObjectMapperUtils.readValue(JSON.toJSONString(newVal), AttachmentFormat.class);
                List<AttachmentFormat> val2 = (List<AttachmentFormat>) oldVal;

                if (val1.size() != val2.size()) {
                    equals = false;
                } else {
                    String collect1 = val1.stream().map(AttachmentFormat::getId).sorted().collect(Collectors.joining(","));
                    String collect2 = val2.stream().map(AttachmentFormat::getId).sorted().collect(Collectors.joining(","));

                    equals = collect2.equals(collect1);
                }


            } else if (ValueType.MULTI_SELECT_DEPARTMENT == valueType || ValueType.MULTI_SELECT_PERSON == valueType || ValueType.PERSON_DEPARTMENT_SELECT == valueType) {
                List<SelectorFormat> val1 = ObjectMapperUtils.readValue(JSON.toJSONString(newVal), SelectorFormat.class);
                List<SelectorFormat> val2 = (List<SelectorFormat>) oldVal;

                if (val1.size() != val2.size()) {
                    equals = false;
                } else {
                    equals = val1.containsAll(val2);
                }

            } else if (ValueType.ADDR_TYPE == valueType || ValueType.MAP_TYPE == valueType) {
                AddrFormat val1 = ObjectMapperUtils.fromJSON(JSON.toJSONString(newVal), AddrFormat.class);
                AddrFormat val2 = (AddrFormat) oldVal;
                equals = val1.equals(val2);
            } else if (ValueType.MULTI_SELECT_TEXT == valueType) {
                List<String> val1 = ObjectMapperUtils.readValue(JSON.toJSONString(newVal), String.class);
                List<String> val2 = (List<String>) oldVal;

                if (val1.size() != val2.size()) {
                    equals = false;
                } else {
                    equals = val1.containsAll(val2);
                }

            } else if (ValueType.DATE == valueType) {
                String val1 = (String) newVal;// 前端提交过来的是string
                String val2 = (String) oldVal;// load 获取过来已转string

                equals = val1.equals(val2);
            } else if (ValueType.BOOLEAN == valueType) {
                Boolean val1 = (Boolean) newVal;
                Boolean val2 = "1".equals(String.valueOf(oldVal));

                equals = val1.equals(val2);
            } else if (ValueType.NUMBER == valueType || ValueType.DECIMAL == valueType) {
                BigDecimal val1 = new BigDecimal(newVal.toString());
                BigDecimal val2 = new BigDecimal(oldVal.toString());

                equals = val1.compareTo(val2) == 0;
            } else {

                equals = newVal.toString().equals(oldVal.toString());
            }
        }

        log.info("字段:{}, newVal={},oldVal={}, equals={}", p.getCode(), newVal, oldVal, equals);

        return equals;
    }

    public static BizException bizException(String errorMessage) {
        ErrorCodeEnum bizError = ErrorCodeEnum.BIZ_EXCEPTION;
        bizError.setErrDesc(errorMessage);
        return new BizException(bizError, errorMessage);
    }

    static {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        String timeZone = StringUtils.isBlank(timeZone = System.getProperty("user.timezone", "Asia/Shanghai")) ? "Asia/Shanghai" : timeZone;
        objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone));
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }
}
